/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usart.h"
#include "adc.h"
#include "DHT11.h"
#include "JW01.h"
#include "oled.h"
#include "gpio.h"
#include "math.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define STATE_IDLE 0
#define STATE_TEMP_UP 1
#define STATE_TEMP_DOWN 2
#define STATE_HUMI_UP 3
#define STATE_HUMI_DOWN 4
#define STATE_TOLU_UP 5
//#define STATE_TOLU_DOWN 6
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

uint8_t UART_Get_Flag=0;
uint8_t UART1_RXD_COUNT = 0;
uint8_t UART1_RXD_BUFF[100] = {0};

float temperature = 0;      //给一个初始化,用与判断
float humidity = 0;

float TVOC = 0;
float CO2 = 0;
float CH2O = 0;

float NH4_ppm = 0;
float Toluene_ppm = 0;

extern UART_HandleTypeDef huart1;
extern uint8_t pData;

uint8_t SYS_STATE = STATE_IDLE;

uint8_t TEMP_UP_LIMIT 		= 28;
uint8_t TEMP_DOWN_LIMIT 	= 24;

uint8_t HUMI_UP_LIMIT 		= 50;
uint8_t HUMI_DOWN_LIMIT 	= 40;

uint8_t TOLU_UP_LIMIT 		= 45;
//uint8_t TOLU_DOWN_LIMIT 	= 25;

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId OLEDTaskHandle;
osThreadId LEDTaskHandle;
osThreadId UartTaskHandle;
osThreadId SensorGetTaskHandle;
osThreadId MonitorTaskHandle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void OLEDTaskFunc(void const * argument);
void LEDTaskFunc(void const * argument);
void UartTaskFunc(void const * argument);
void SensorGetTaskFunc(void const * argument);
void MonitorTaskFunc(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of OLEDTask */
  osThreadDef(OLEDTask, OLEDTaskFunc, osPriorityNormal, 0, 256);
  OLEDTaskHandle = osThreadCreate(osThread(OLEDTask), NULL);

  /* definition and creation of LEDTask */
  osThreadDef(LEDTask, LEDTaskFunc, osPriorityIdle, 0, 256);
  LEDTaskHandle = osThreadCreate(osThread(LEDTask), NULL);

  /* definition and creation of UartTask */
  osThreadDef(UartTask, UartTaskFunc, osPriorityAboveNormal, 0, 256);
  UartTaskHandle = osThreadCreate(osThread(UartTask), NULL);

  /* definition and creation of SensorGetTask */
  osThreadDef(SensorGetTask, SensorGetTaskFunc, osPriorityNormal, 0, 256);
  SensorGetTaskHandle = osThreadCreate(osThread(SensorGetTask), NULL);

  /* definition and creation of MonitorTask */
  osThreadDef(MonitorTask, MonitorTaskFunc, osPriorityNormal, 0, 256);
  MonitorTaskHandle = osThreadCreate(osThread(MonitorTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_OLEDTaskFunc */
/**
  * @brief  Function implementing the OLEDTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_OLEDTaskFunc */
void OLEDTaskFunc(void const * argument)
{
  /* USER CODE BEGIN OLEDTaskFunc */
	uint8_t LAST_STATE = SYS_STATE;
	OLED_Init();

	OLED_ShowString(0,0,(uint8_t *)"temp :", 12 ,1);
	OLED_ShowString(0,1,(uint8_t *)"humi :", 12 ,1);
	OLED_ShowString(0,2,(uint8_t *)"smoke:", 12 ,1);
	OLED_ShowString(0,3,(uint8_t *)"CO2  :", 12 ,1);

  /* Infinite loop */
  for(;;)
  {
	  if( LAST_STATE != SYS_STATE ){
		  OLED_Clear();
		  LAST_STATE = SYS_STATE;

		  switch (SYS_STATE) {
			case STATE_IDLE:
				OLED_ShowString(0,0,(uint8_t *)"temp :", 12 ,1);
				OLED_ShowString(0,1,(uint8_t *)"humi :", 12 ,1);
				OLED_ShowString(0,2,(uint8_t *)"smoke:", 12 ,1);
				OLED_ShowString(0,3,(uint8_t *)"CO2  :", 12 ,1);
				break;
			case STATE_TEMP_UP:		OLED_ShowString(0,0,(uint8_t *)"temp up limit:", 12 ,1);	break;
			case STATE_TEMP_DOWN: 	OLED_ShowString(0,0,(uint8_t *)"temp down limit:", 12 ,1);	break;
			case STATE_HUMI_UP:		OLED_ShowString(0,0,(uint8_t *)"humi up limit:", 12 ,1);	break;
			case STATE_HUMI_DOWN:	OLED_ShowString(0,0,(uint8_t *)"humi down limit:", 12 ,1);	break;
			case STATE_TOLU_UP:		OLED_ShowString(0,0,(uint8_t *)"smoke up limit:", 12 ,1);	break;
//			case STATE_TOLU_DOWN:	OLED_ShowString(0,0,(uint8_t *)"smoke down limit", 12 ,1);	break;
			default:				break;
		}
	  }

	  switch (SYS_STATE) {
		case STATE_IDLE:
			OLED_Show_Decimal(55,0,temperature,12,1);
			OLED_Show_Decimal(55,1,humidity,12,1);
			OLED_Show_Decimal(55,2,Toluene_ppm,12,1);
			OLED_Show_Decimal(55,3,CO2,12,1);
			break;
		case STATE_TEMP_UP:		OLED_ShowNum(20,2,TEMP_UP_LIMIT,3,16,1);		break;
		case STATE_TEMP_DOWN:	OLED_ShowNum(20,2,TEMP_DOWN_LIMIT,3,16,1);		break;
		case STATE_HUMI_UP:		OLED_ShowNum(20,2,HUMI_UP_LIMIT,3,16,1);		break;
		case STATE_HUMI_DOWN:	OLED_ShowNum(20,2,HUMI_DOWN_LIMIT,3,16,1);		break;
		case STATE_TOLU_UP:		OLED_ShowNum(20,2,TOLU_UP_LIMIT,3,16,1);		break;
//		case STATE_TOLU_DOWN:	OLED_ShowNum(20,2,TOLU_DOWN_LIMIT,3,16,1);		break;
		default:				break;
	}

	  osDelay(200);
  }
  /* USER CODE END OLEDTaskFunc */
}

/* USER CODE BEGIN Header_LEDTaskFunc */
/**
* @brief Function implementing the LEDTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_LEDTaskFunc */
void LEDTaskFunc(void const * argument)
{
  /* USER CODE BEGIN LEDTaskFunc */

	uint8_t KEY=0;

  /* Infinite loop */
  for(;;)
  {
	  KEY = Get_Key_Value(0);
	  switch (KEY) {
		case 1:
			switch (SYS_STATE) {
				case STATE_IDLE:		break;
				case STATE_TEMP_UP:		TEMP_UP_LIMIT++;	break;
				case STATE_TEMP_DOWN:	TEMP_DOWN_LIMIT++;		break;
				case STATE_HUMI_UP:		HUMI_UP_LIMIT++;	break;
				case STATE_HUMI_DOWN:	HUMI_DOWN_LIMIT++;		break;
				case STATE_TOLU_UP:		TOLU_UP_LIMIT++;	break;
//				case STATE_TOLU_DOWN:	TOLU_DOWN_LIMIT++;			break;
				default:				break;
			}
			break;
		case 2:
			switch (SYS_STATE) {
				case STATE_IDLE:		break;
				case STATE_TEMP_UP:		TEMP_UP_LIMIT--;	break;
				case STATE_TEMP_DOWN:	TEMP_DOWN_LIMIT--;		break;
				case STATE_HUMI_UP:		HUMI_UP_LIMIT--;	break;
				case STATE_HUMI_DOWN:	HUMI_DOWN_LIMIT--;		break;
				case STATE_TOLU_UP:		TOLU_UP_LIMIT--;	break;
//				case STATE_TOLU_DOWN:	TOLU_DOWN_LIMIT--;			break;
				default:				break;
			}
			break;
		case 3:
			switch (SYS_STATE) {
				case STATE_IDLE:		SYS_STATE = STATE_TEMP_UP;		break;
				case STATE_TEMP_UP:		SYS_STATE = STATE_TEMP_DOWN;	break;
				case STATE_TEMP_DOWN:	SYS_STATE = STATE_HUMI_UP;		break;
				case STATE_HUMI_UP:		SYS_STATE = STATE_HUMI_DOWN;	break;
				case STATE_HUMI_DOWN:	SYS_STATE = STATE_TOLU_UP;		break;
				case STATE_TOLU_UP:		SYS_STATE = STATE_IDLE;			break;
//				case STATE_TOLU_DOWN:	SYS_STATE = STATE_IDLE;			break;
				default:				break;
			}
			break;
		case 4:
			SYS_STATE = STATE_IDLE;
			break;
		default:
			break;
	}
	  HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
	  osDelay(200);
  }
  /* USER CODE END LEDTaskFunc */
}

/* USER CODE BEGIN Header_UartTaskFunc */
/**
* @brief Function implementing the UartTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_UartTaskFunc */
void UartTaskFunc(void const * argument)
{
  /* USER CODE BEGIN UartTaskFunc */
  /* Infinite loop */
  for(;;)
  {
	  osDelay(200);
	  if( UART_Get_Flag ){
		  UART_Get_Flag = 0;
		  JW01_Get_Air_State(UART1_RXD_BUFF , &TVOC , &CO2 , &CH2O);
		  HAL_UART_Receive_IT( &huart1, &pData, 1);
	  }
  }
  /* USER CODE END UartTaskFunc */
}

/* USER CODE BEGIN Header_SensorGetTaskFunc */
/**
* @brief Function implementing the SensorGetTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_SensorGetTaskFunc */
void SensorGetTaskFunc(void const * argument)
{
  /* USER CODE BEGIN SensorGetTaskFunc */
	uint16_t adcValues = 0;
	float Voltage=0;

	//上电先检�????,电路是非有问�????
	DHT11_REST();                 //复位DHT11
	while(DHT11_Check())          //�????测DHT11连接
	{
		My_printf ("No Connect!\r\n");
//		osDelay(500);
	}
//	My_printf ("Success!\r\n");

  /* Infinite loop */
  for(;;)
  {
	  osDelay(1000);

	  /*---------------------------------------------------------------*/
	  /*------------------------------MQ-2-----------------------------*/
	  /*---------------------------------------------------------------*/
	  HAL_ADC_Start(&hadc1);
	  HAL_ADC_PollForConversion(&hadc1, 50);
	  if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
		  adcValues = HAL_ADC_GetValue(&hadc1);

	  Voltage = 3.3*adcValues/4096;
	  //氨气（NH4）的C语言计算公式
	  NH4_ppm = pow((6.467*10*Voltage)/(5-Voltage),(1.0/0.3962));

	  //甲苯（toluene）的C语言计算公式
	  Toluene_ppm = pow((3.367*10*Voltage)/(5-Voltage),(1.0/0.3123));
//	  My_printf("Voltage:%f\r\nNH4_ppm:%f\r\nToluene_ppm:%f\r\n",Voltage,NH4_ppm,Toluene_ppm);
	  /*---------------------------------------------------------------*/


	  /*---------------------------------------------------------------*/
	  /*---------------------------DHT-11------------------------------*/
	  /*---------------------------------------------------------------*/

	  DHT11_Read_Data(&humidity,&temperature);
//	  My_printf("temperature : %5.2f ^C\r\n ",temperature) ;
//	  My_printf ("humidity : %5.2f %% \r\n",humidity);

	  /*---------------------------------------------------------------*/

  }
  /* USER CODE END SensorGetTaskFunc */
}

/* USER CODE BEGIN Header_MonitorTaskFunc */
/**
* @brief Function implementing the MonitorTask thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_MonitorTaskFunc */
void MonitorTaskFunc(void const * argument)
{
  /* USER CODE BEGIN MonitorTaskFunc */

	uint8_t temp_sluggish = 0;
	uint8_t humi_sluggish = 0;
	uint8_t smoke_sluggish = 0;

	uint8_t ON_OFF=0;
	uint8_t LAST_ON_OFF = ON_OFF;

	osDelay(5000);
  /* Infinite loop */
  for(;;)
  {

	  /*-------------------------------temp--------------------------------*/
	  if( temperature - TEMP_UP_LIMIT > temp_sluggish ) // gao le
	  {
		  // open fan1,close heat
		  HAL_GPIO_WritePin(FAN_1_EN_GPIO_Port, FAN_1_EN_Pin,1);
		  HAL_GPIO_WritePin(AIR_HEAT_EN_GPIO_Port, AIR_HEAT_EN_Pin,0);
	  } else if ( TEMP_DOWN_LIMIT - temperature  > temp_sluggish )
	  {
		  // close fan1,open heat
		  HAL_GPIO_WritePin(FAN_1_EN_GPIO_Port, FAN_1_EN_Pin,0);
		  HAL_GPIO_WritePin(AIR_HEAT_EN_GPIO_Port, AIR_HEAT_EN_Pin,1);
	  } else
	  {
		  // close fan1,close heat
		  HAL_GPIO_WritePin(FAN_1_EN_GPIO_Port, FAN_1_EN_Pin,0);
		  HAL_GPIO_WritePin(AIR_HEAT_EN_GPIO_Port, AIR_HEAT_EN_Pin,0);
	  }

	  /*-------------------------------humi--------------------------------*/
	  if( humidity - HUMI_UP_LIMIT > humi_sluggish ) // gao le
	  {
		  // open fan2,close humi
		  ON_OFF = 0 ;
		  if( LAST_ON_OFF != ON_OFF ){
			  LAST_ON_OFF = ON_OFF ;
			  HUM_STATE_SET(ON_OFF);
		  }
		  HAL_GPIO_WritePin(FAN_2_EN_GPIO_Port, FAN_2_EN_Pin,1);
	  } else if ( HUMI_DOWN_LIMIT - humidity  > humi_sluggish )
	  {
		  // close fan2,open humi
		  ON_OFF = 1 ;
		  if( LAST_ON_OFF != ON_OFF ){
			  LAST_ON_OFF = ON_OFF ;
			  HUM_STATE_SET(ON_OFF);
		  }
		  HAL_GPIO_WritePin(FAN_2_EN_GPIO_Port, FAN_2_EN_Pin,0);
	  } else
	  {
		  // close fan2,close humi
		  ON_OFF = 0 ;
		  if( LAST_ON_OFF != ON_OFF ){
			  LAST_ON_OFF = ON_OFF ;
			  HUM_STATE_SET(ON_OFF);
		  }
		  HAL_GPIO_WritePin(FAN_2_EN_GPIO_Port, FAN_2_EN_Pin,0);
	  }

	  /*-------------------------------smoke--------------------------------*/
	  if( Toluene_ppm - TOLU_UP_LIMIT > smoke_sluggish ) // gao le
	  {
		  // beep ring
		  HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin,0);
		  osDelay(200);
		  HAL_GPIO_WritePin(BEEP_GPIO_Port, BEEP_Pin,1);
		  osDelay(200);
	  }

	  osDelay(1000);
  }
  /* USER CODE END MonitorTaskFunc */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

